Skip to content

fix: Spec for list exp and get config endpoints#916

Open
ayushjain17 wants to merge 3 commits intomainfrom
fix/smithy-consistency
Open

fix: Spec for list exp and get config endpoints#916
ayushjain17 wants to merge 3 commits intomainfrom
fix/smithy-consistency

Conversation

@ayushjain17
Copy link
Collaborator

@ayushjain17 ayushjain17 commented Mar 16, 2026

Problem

Describe the problem you are trying to solve here

Solution

Provide a brief summary of your solution so that reviewers can understand your code

Environment variable changes

What ENVs need to be added or changed

Pre-deployment activity

Things needed to be done before deploying this change (if any)

Post-deployment activity

Things needed to be done after deploying this change (if any)

API changes

Endpoint Method Request body Response Body
API GET/POST, etc request response

Possible Issues in the future

Describe any possible issues that could occur because of this change

Summary by CodeRabbit

  • New Features

    • Added If-Modified-Since header support to config and list endpoints for improved caching capabilities.
    • Added context parameter to experiment listing operations for dimensional filtering.
    • Added last-modified response headers to list operations.
  • Bug Fixes / Improvements

    • Simplified config retrieval by consolidating fast and standard paths.
    • Migrated list endpoints to POST method with dedicated "/list" routes for better scalability.
  • Removals

    • Removed GetConfigFast operation; use standard GetConfig instead.
    • Removed audit_id field from config responses.

@ayushjain17 ayushjain17 requested a review from a team as a code owner March 16, 2026 09:52
@semanticdiff-com
Copy link

semanticdiff-com bot commented Mar 16, 2026

Review changes with  SemanticDiff

Changed Files
File Status
  docs/docs/api/get-config.StatusCodes.json  100% smaller
  docs/docs/api/list-experiment.StatusCodes.json  99% smaller
  docs/docs/api/list-experiment-groups.StatusCodes.json  99% smaller
  clients/java/sdk/src/main/java/io/juspay/superposition/model/Config.java  92% smaller
  docs/docs/api/list-experiment.ParamsDetails.json  88% smaller
  docs/docs/api/list-experiment-groups.ParamsDetails.json  86% smaller
  crates/frontend/src/pages/experiment_group_listing.rs  70% smaller
  docs/docs/api/get-config.ParamsDetails.json  68% smaller
  docs/docs/api/Superposition.openapi.json  62% smaller
  crates/superposition/src/resolve/handlers.rs  61% smaller
  docs/docs/api/sidebar.ts  53% smaller
  crates/superposition_types/src/contextual.rs  50% smaller
  crates/frontend/src/api.rs  49% smaller
  clients/java/sdk/src/main/java/io/juspay/superposition/model/ListExperimentInput.java  39% smaller
  crates/context_aware_config/src/api/config/handlers.rs  38% smaller
  crates/context_aware_config/src/api/context/handlers.rs  38% smaller
  clients/python/sdk/superposition_sdk/_private/schemas.py  32% smaller
  clients/python/sdk/superposition_sdk/deserialize.py  30% smaller
  clients/java/sdk/src/main/java/io/juspay/superposition/model/ListExperimentGroupsInput.java  29% smaller
  crates/superposition_types/src/api/experiment_groups.rs  25% smaller
  crates/frontend/src/pages/experiment_group_listing/filter.rs  23% smaller
  crates/experimentation_platform/src/api/experiment_groups/handlers.rs  20% smaller
  crates/superposition_sdk/src/operation/list_experiment_groups.rs  19% smaller
  crates/superposition_sdk/src/operation/list_experiment.rs  17% smaller
  clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigInput.java  15% smaller
  crates/experimentation_platform/src/api/experiments/handlers.rs  14% smaller
  clients/java/sdk/src/main/java/io/juspay/superposition/client/SuperpositionAsyncClient.java  10% smaller
  clients/java/sdk/src/main/java/io/juspay/superposition/client/SuperpositionClient.java  10% smaller
  clients/java/sdk/src/main/java/io/juspay/superposition/model/ExperimentGroup.java  10% smaller
  clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigOutput.java  9% smaller
  clients/java/sdk/src/main/java/io/juspay/superposition/model/ListExperimentGroupsOutput.java  7% smaller
  clients/java/sdk/src/main/java/io/juspay/superposition/model/ListExperimentOutput.java  7% smaller
  clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigJsonInput.java  7% smaller
  clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigTomlInput.java  7% smaller
  crates/service_utils/src/service/types.rs  6% smaller
  clients/javascript/sdk/src/protocols/Aws_restJson1.ts  5% smaller
  crates/superposition_sdk/src/operation/get_config_json/_get_config_json_input.rs  5% smaller
  crates/superposition_sdk/src/operation/get_config_toml/_get_config_toml_input.rs  5% smaller
  crates/context_aware_config/src/api/config/helpers.rs  3% smaller
  crates/frontend/src/components/experiment_form.rs  2% smaller
  crates/service_utils/src/helpers.rs  2% smaller
  clients/python/sdk/superposition_sdk/serialize.py  1% smaller
  clients/python/sdk/superposition_sdk/config.py  1% smaller
  Cargo.lock Unsupported file format
  clients/haskell/sdk/Io/Superposition/Command/GetConfigFast.hs Unsupported file format
  clients/haskell/sdk/Io/Superposition/Model/GetConfigFastInput.hs Unsupported file format
  clients/haskell/sdk/Io/Superposition/Model/GetConfigFastOutput.hs Unsupported file format
  clients/haskell/sdk/Io/Superposition/Model/GetConfigInput.hs Unsupported file format
  clients/haskell/sdk/Io/Superposition/Model/GetConfigJsonInput.hs Unsupported file format
  clients/haskell/sdk/Io/Superposition/Model/GetConfigOutput.hs Unsupported file format
  clients/haskell/sdk/Io/Superposition/Model/GetConfigTomlInput.hs Unsupported file format
  clients/haskell/sdk/Io/Superposition/Model/ListExperimentGroupsInput.hs Unsupported file format
  clients/haskell/sdk/Io/Superposition/Model/ListExperimentGroupsOutput.hs Unsupported file format
  clients/haskell/sdk/Io/Superposition/Model/ListExperimentInput.hs Unsupported file format
  clients/haskell/sdk/Io/Superposition/Model/ListExperimentOutput.hs Unsupported file format
  clients/haskell/sdk/SuperpositionSDK.cabal Unsupported file format
  clients/java/sdk/src/main/java/io/juspay/superposition/client/SuperpositionAsyncClientImpl.java  0% smaller
  clients/java/sdk/src/main/java/io/juspay/superposition/client/SuperpositionClientImpl.java  0% smaller
  clients/java/sdk/src/main/java/io/juspay/superposition/model/Experiments.java  0% smaller
  clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigFast.java  0% smaller
  clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigFastInput.java  0% smaller
  clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigFastOutput.java  0% smaller
  clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigJson.java  0% smaller
  clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigToml.java  0% smaller
  clients/java/sdk/src/main/java/io/juspay/superposition/model/ListExperiment.java  0% smaller
  clients/java/sdk/src/main/java/io/juspay/superposition/model/ListExperimentGroups.java  0% smaller
  clients/javascript/sdk/src/Superposition.ts  0% smaller
  clients/javascript/sdk/src/SuperpositionClient.ts  0% smaller
  clients/javascript/sdk/src/commands/GetConfigCommand.ts  0% smaller
  clients/javascript/sdk/src/commands/GetConfigFastCommand.ts  0% smaller
  clients/javascript/sdk/src/commands/GetConfigJsonCommand.ts  0% smaller
  clients/javascript/sdk/src/commands/GetConfigTomlCommand.ts  0% smaller
  clients/javascript/sdk/src/commands/ListExperimentCommand.ts  0% smaller
  clients/javascript/sdk/src/commands/ListExperimentGroupsCommand.ts  0% smaller
  clients/javascript/sdk/src/commands/index.ts  0% smaller
  clients/javascript/sdk/src/models/models_0.ts  0% smaller
  clients/python/sdk/superposition_sdk/client.py  0% smaller
  clients/python/sdk/superposition_sdk/models.py  0% smaller
  crates/context_aware_config/Cargo.toml Unsupported file format
  crates/experimentation_client/src/lib.rs  0% smaller
  crates/frontend/src/pages/experiment_list/filter.rs  0% smaller
  crates/service_utils/src/redis.rs  0% smaller
  crates/superposition_sdk/src/client.rs  0% smaller
  crates/superposition_sdk/src/client/customize.rs  0% smaller
  crates/superposition_sdk/src/client/get_config.rs  0% smaller
  crates/superposition_sdk/src/client/get_config_fast.rs  0% smaller
  crates/superposition_sdk/src/client/get_config_json.rs  0% smaller
  crates/superposition_sdk/src/client/get_config_toml.rs  0% smaller
  crates/superposition_sdk/src/client/list_experiment.rs  0% smaller
  crates/superposition_sdk/src/client/list_experiment_groups.rs  0% smaller
  crates/superposition_sdk/src/error_meta.rs  0% smaller
  crates/superposition_sdk/src/operation.rs  0% smaller
  crates/superposition_sdk/src/operation/get_config/_get_config_input.rs Unsupported file format
  crates/superposition_sdk/src/operation/get_config/_get_config_output.rs Unsupported file format
  crates/superposition_sdk/src/operation/get_config/builders.rs Unsupported file format
  crates/superposition_sdk/src/operation/get_config_fast.rs  0% smaller
  crates/superposition_sdk/src/operation/get_config_fast/_get_config_fast_input.rs  0% smaller
  crates/superposition_sdk/src/operation/get_config_fast/_get_config_fast_output.rs  0% smaller
  crates/superposition_sdk/src/operation/get_config_fast/builders.rs  0% smaller
  crates/superposition_sdk/src/operation/get_config_json.rs  0% smaller
  crates/superposition_sdk/src/operation/get_config_json/builders.rs  0% smaller
  crates/superposition_sdk/src/operation/get_config_toml.rs  0% smaller
  crates/superposition_sdk/src/operation/get_config_toml/builders.rs  0% smaller
  crates/superposition_sdk/src/operation/list_experiment/_list_experiment_input.rs Unsupported file format
  crates/superposition_sdk/src/operation/list_experiment/_list_experiment_output.rs Unsupported file format
  crates/superposition_sdk/src/operation/list_experiment/builders.rs Unsupported file format
  crates/superposition_sdk/src/operation/list_experiment_groups/_list_experiment_groups_input.rs Unsupported file format
  crates/superposition_sdk/src/operation/list_experiment_groups/_list_experiment_groups_output.rs Unsupported file format
  crates/superposition_sdk/src/operation/list_experiment_groups/builders.rs Unsupported file format
  crates/superposition_sdk/src/protocol_serde.rs  0% smaller
  crates/superposition_sdk/src/protocol_serde/shape_get_config.rs  0% smaller
  crates/superposition_sdk/src/protocol_serde/shape_get_config_fast.rs  0% smaller
  crates/superposition_sdk/src/protocol_serde/shape_get_config_fast_output.rs  0% smaller
  crates/superposition_sdk/src/protocol_serde/shape_get_config_json.rs  0% smaller
  crates/superposition_sdk/src/protocol_serde/shape_get_config_output.rs  0% smaller
  crates/superposition_sdk/src/protocol_serde/shape_get_config_toml.rs  0% smaller
  crates/superposition_sdk/src/protocol_serde/shape_list_experiment.rs  0% smaller
  crates/superposition_sdk/src/protocol_serde/shape_list_experiment_groups.rs  0% smaller
  crates/superposition_sdk/src/protocol_serde/shape_list_experiment_groups_input.rs  0% smaller
  crates/superposition_sdk/src/protocol_serde/shape_list_experiment_groups_output.rs  0% smaller
  crates/superposition_sdk/src/protocol_serde/shape_list_experiment_input.rs  0% smaller
  crates/superposition_sdk/src/protocol_serde/shape_list_experiment_output.rs  0% smaller
  crates/superposition_sdk/src/serde_util.rs  0% smaller
  crates/superposition_sdk/src/types.rs  0% smaller
  crates/superposition_sdk/src/types/builders.rs  0% smaller
  crates/superposition_types/src/api/experiments.rs  0% smaller
  crates/superposition_types/src/config.rs  0% smaller
  crates/superposition_types/src/database/models/cac.rs  0% smaller
  crates/superposition_types/src/database/models/experimentation.rs  0% smaller
  docs/docs/api/get-config-fast.ParamsDetails.json  0% smaller
  docs/docs/api/get-config-fast.RequestSchema.json  0% smaller
  docs/docs/api/get-config-fast.StatusCodes.json  0% smaller
  docs/docs/api/get-config-fast.api.mdx Unsupported file format
  docs/docs/api/get-config-json.ParamsDetails.json  0% smaller
  docs/docs/api/get-config-json.api.mdx Unsupported file format
  docs/docs/api/get-config-toml.ParamsDetails.json  0% smaller
  docs/docs/api/get-config-toml.api.mdx Unsupported file format
  docs/docs/api/get-config.api.mdx Unsupported file format
  docs/docs/api/list-experiment-groups.RequestSchema.json  0% smaller
  docs/docs/api/list-experiment-groups.api.mdx Unsupported file format
  docs/docs/api/list-experiment.RequestSchema.json  0% smaller
  docs/docs/api/list-experiment.api.mdx Unsupported file format
  smithy/models/config.smithy Unsupported file format
  smithy/models/experiment_groups.smithy Unsupported file format
  smithy/models/experiments.smithy Unsupported file format
  smithy/patches/java.patch Unsupported file format
  smithy/patches/python.patch Unsupported file format
  tests/src/config.test.ts  0% smaller
  tests/src/experiment_groups.test.ts  0% smaller
  tests/src/experiments.test.ts  0% smaller

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 16, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1096b00a-dca7-4002-88dc-145032155b95

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

This pull request removes the GetConfigFast operation and its models across all SDKs (Haskell, Java, JavaScript, Python, Rust), removes audit_id from GetConfigOutput, and adds If-Modified-Since header support and last_modified/last_modified_at fields to multiple operations. ListExperiment and ListExperimentGroups operations are migrated from GET to POST with request bodies. Frontend and backend changes introduce dimension-based filtering for experiment groups.

Changes

Cohort / File(s) Summary
GetConfigFast Removal - Haskell SDK
clients/haskell/sdk/Io/Superposition/Command/GetConfigFast.hs, clients/haskell/sdk/Io/Superposition/Model/GetConfigFast*.hs, clients/haskell/sdk/SuperpositionSDK.cabal
Removed entire GetConfigFast operation, input/output types, and module exports across Haskell SDK.
GetConfigFast Removal - Java SDK
clients/java/sdk/src/main/java/io/juspay/superposition/client/SuperpositionAsyncClient*.java, clients/java/sdk/src/main/java/io/juspay/superposition/client/SuperpositionClient*.java, clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigFast*.java, clients/java/sdk/src/main/java/io/juspay/superposition/model/Config.java
Deleted GetConfigFast operation class, input/output model classes, and removed from client interfaces across Java SDK.
GetConfigFast Removal - JavaScript SDK
clients/javascript/sdk/src/Superposition.ts, clients/javascript/sdk/src/SuperpositionClient.ts, clients/javascript/sdk/src/commands/GetConfigFastCommand.ts, clients/javascript/sdk/src/commands/index.ts, clients/javascript/sdk/src/protocols/Aws_restJson1.ts
Removed GetConfigFastCommand import/export, deleted command class, and removed protocol serialization/deserialization support.
GetConfigFast Removal - Python SDK
clients/python/sdk/superposition_sdk/_private/schemas.py, clients/python/sdk/superposition_sdk/client.py, clients/python/sdk/superposition_sdk/config.py, clients/python/sdk/superposition_sdk/models.py
Removed GET_CONFIG_FAST operation, input/output types, and serialization/deserialization functions from Python SDK.
GetConfigFast Removal - Rust SDK
crates/superposition_sdk/src/client/get_config_fast.rs, crates/superposition_sdk/src/operation/get_config_fast*.rs, crates/superposition_sdk/src/protocol_serde/shape_get_config_fast*.rs, crates/superposition_sdk/src/operation.rs, crates/superposition_sdk/src/client.rs
Removed GetConfigFast operation orchestration, input/output structures, protocol serialization, and client methods.
Audit ID Removal from GetConfig
clients/haskell/sdk/Io/Superposition/Model/GetConfigOutput.hs, clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigOutput.java, clients/javascript/sdk/src/models/models_0.ts, clients/python/sdk/superposition_sdk/deserialize.py, crates/superposition_sdk/src/operation/get_config/_get_config_output.rs, crates/superposition_sdk/src/protocol_serde/shape_get_config_output.rs, smithy/models/config.smithy
Removed audit_id field and x-audit-id header parsing from GetConfigOutput across all SDKs and Smithy models.
If-Modified-Since Header Support
clients/haskell/sdk/Io/Superposition/Model/GetConfigInput.hs, clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigInput.java, clients/javascript/sdk/src/commands/GetConfigCommand.ts, clients/python/sdk/superposition_sdk/serialize.py, crates/superposition_sdk/src/operation/get_config/_get_config_input.rs, crates/superposition_sdk/src/operation/get_config/builders.rs, crates/superposition_sdk/src/protocol_serde/shape_get_config.rs, smithy/models/config.smithy
Added if_modified_since (DateTime) field to GetConfig input with If-Modified-Since HTTP header support and 304 caching documentation across all SDKs.
ListExperiment POST Migration & Fields
clients/haskell/sdk/Io/Superposition/Model/ListExperimentInput.hs, clients/java/sdk/src/main/java/io/juspay/superposition/model/ListExperiment*.java, clients/javascript/sdk/src/models/models_0.ts, clients/python/sdk/superposition_sdk/serialize.py, crates/superposition_sdk/src/operation/list_experiment*.rs, crates/superposition_sdk/src/protocol_serde/shape_list_experiment*.rs, smithy/models/experiments.smithy
Changed ListExperiment from GET /experiments to POST /experiments/list; added if_modified_since header and context map fields to input; added last_modified_at to output.
ListExperimentGroups POST Migration & Fields
clients/haskell/sdk/Io/Superposition/Model/ListExperimentGroupsInput.hs, clients/java/sdk/src/main/java/io/juspay/superposition/model/ListExperimentGroups*.java, clients/javascript/sdk/src/models/models_0.ts, clients/python/sdk/superposition_sdk/serialize.py, crates/superposition_sdk/src/operation/list_experiment_groups*.rs, crates/superposition_sdk/src/protocol_serde/shape_list_experiment_groups*.rs, smithy/models/experiment_groups.smithy
Changed ListExperimentGroups from GET /experiment-groups to POST /experiment-groups/list; added if_modified_since and context fields to input; added last_modified to output.
Backend Service - Config Handlers
crates/context_aware_config/src/api/config/handlers.rs, crates/context_aware_config/src/api/config/helpers.rs, crates/service_utils/src/service/types.rs
Refactored header manipulation: moved add_last_modified_to_header and add_config_version_to_header from helpers to AppHeader associated functions; updated handler imports and calls.
Backend Service - Experiment Groups Listing
crates/experimentation_platform/src/api/experiment_groups/handlers.rs, crates/experimentation_platform/src/api/experiments/handlers.rs, crates/superposition_types/src/api/experiment_groups.rs, crates/superposition_types/src/api/experiments.rs
Added dimension-based filtering to experiment groups listing; added ExpGroupListRequest and ExperimentListRequest types; implemented If-Modified-Since caching logic and last-modified header handling in list_handler.
Frontend - Experiment Group Listing
crates/frontend/src/pages/experiment_group_listing.rs, crates/frontend/src/pages/experiment_group_listing/filter.rs, crates/frontend/src/api.rs, crates/frontend/src/components/experiment_form.rs
Added DimensionQuery parameter to experiment groups listing; extended FilterSummary and ExperimentGroupFilterWidget to support dimension-based filtering and context UI; added dimension_params propagation through API calls.
Database & Utilities
crates/superposition_types/src/database/models/experimentation.rs, crates/service_utils/src/redis.rs, crates/service_utils/src/helpers.rs, crates/superposition_sdk/src/types.rs, crates/superposition_sdk/src/types/builders.rs
Added Contextual trait implementation for ExperimentGroup; added EXPERIMENT_GROUPS_LAST_MODIFIED_KEY_SUFFIX constant; minor cleanup and reordering of public exports.
Protocol Serialization - Rust SDK
crates/superposition_sdk/src/protocol_serde.rs, crates/superposition_sdk/src/protocol_serde/shape_list_experiment*.rs, crates/superposition_sdk/src/serde_util.rs
Added serialization functions for ListExperiment/ListExperimentGroups inputs and header parsing for last_modified fields; added error correction defaults for new DateTime fields.
Dependency Changes
crates/context_aware_config/Cargo.toml
Removed actix-http dependency from context_aware_config crate.
Context Handler Refactor
crates/experimentation_platform/src/api/context/handlers.rs
Simplified is_v2 computation in bulk_operations_handler from mutable flag to inline boolean match expression.
API Documentation
docs/docs/api/Superposition.openapi.json, docs/docs/api/get-config.api.mdx, docs/docs/api/get-config-fast.api.mdx, docs/docs/api/list-experiment*.api.mdx, docs/docs/api/sidebar.ts
Updated OpenAPI schema with new headers/request bodies; removed GetConfigFast documentation; updated list endpoints to reflect POST method and new response headers; removed fast-config sidebar entry.
Smithy Models & Patches
smithy/models/config.smithy, smithy/models/experiment_groups.smithy, smithy/models/experiments.smithy, smithy/patches/java.patch, smithy/patches/python.patch
Updated Smithy operation definitions for GetConfig, ListExperiment, and ListExperimentGroups; moved collectionOperations references; added If-Modified-Since and context fields; refactored Map.of to Map.ofEntries in Java patch.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~90+ minutes

Possibly related PRs

Suggested labels

feature, breaking-change, sdk-update

Suggested reviewers

  • mahatoankitkumar
  • knutties

Poem

🐰 The config-fast path hops away, no more speed,
But If-Modified-Since now plants caching seeds.
POST requests bloom where GET once dwelled,
With dimensions dancing—experiment stories retold!
Headers spring forth (last-modified rings true),
Audit IDs fade as new fields come through. 🌿✨

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/smithy-consistency

@ayushjain17 ayushjain17 force-pushed the fix/smithy-consistency branch from 56b3166 to e7359a1 Compare March 16, 2026 09:52
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
clients/haskell/sdk/SuperpositionSDK.cabal (1)

3-3: ⚠️ Potential issue | 🟠 Major

Bump package version for this public API change.

Removing modules from exposed-modules is a breaking SDK surface change, but Line 3 still keeps version: 0.0.1. Please increment the package version per your release policy so downstream consumers can detect and adopt the break safely.

📦 Suggested update
-version: 0.0.1
+version: 0.1.0

Also applies to: 20-323

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@clients/haskell/sdk/SuperpositionSDK.cabal` at line 3, The package still
lists "version: 0.0.1" in SuperpositionSDK.cabal despite removing modules from
exposed-modules (a breaking public API change); update the version field in
SuperpositionSDK.cabal to the next release version appropriate for a breaking
change (per your release policy) so downstream consumers can detect the change,
e.g., replace "version: 0.0.1" with the new version string.
clients/haskell/sdk/Io/Superposition/Model/GetConfigInput.hs (1)

137-148: ⚠️ Potential issue | 🟠 Major

Handle 304 Not Modified responses for conditional requests.

The If-Modified-Since header enables HTTP conditional requests that return 304 Not Modified responses, but the SDK does not handle this status code. When a 304 is received, parseOutput will reject it (outside the 200-299 range) and return an UnexpectedError with message "Un-expected status code." This breaks the caching semantics of conditional requests.

Add a 304 Not Modified handler that returns a cached response, empty/default GetConfigOutput, or integrates with the HTTP client's cache headers. Alternatively, remove the If-Modified-Since header if conditional requests are not intended to be supported.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@clients/haskell/sdk/Io/Superposition/Model/GetConfigInput.hs` around lines
137 - 148, The request builder for GetConfigInput currently sends an
"If-Modified-Since" header (see IntoRequestBuilder/GetConfigInput and
intoRequestBuilder calling serHeader "If-Modified-Since") but there is no 304
handling; update the response parsing for this operation (the GetConfigOutput
parse function or parseOutput for GetConfigInput/GetConfigOutput) to explicitly
handle HTTP 304 by returning an appropriate cached/empty/default GetConfigOutput
(or a sentinel indicating "NotModified") instead of treating 304 as an
unexpected status, or if conditional requests are not supported, remove the
serHeader "If-Modified-Since" from intoRequestBuilder to avoid sending
conditional requests altogether. Ensure you reference and update the parse
function that currently rejects non-2xx responses so it treats 304 as a valid
branch.
crates/experimentation_platform/src/api/experiments/handlers.rs (1)

1021-1029: ⚠️ Potential issue | 🟠 Major

POST conditional caching can break due to timestamp format mismatch.

With Line 1036 enabling POST/Smithy flow, If-Modified-Since parsing at Line 1026 still accepts only RFC2822. Smithy clients using RFC3339 won’t hit the 304 path.

💡 Suggested fix
     let last_modified = req
         .headers()
         .get("If-Modified-Since")
         .and_then(|header_val| header_val.to_str().ok())
         .and_then(|header_str| {
-            DateTime::parse_from_rfc2822(header_str)
+            DateTime::parse_from_rfc2822(header_str)
+                .or_else(|_| DateTime::parse_from_rfc3339(header_str))
                 .map(|datetime| datetime.with_timezone(&Utc))
                 .ok()
         });

Also applies to: 1036-1043

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/experimentation_platform/src/api/experiments/handlers.rs` around lines
1021 - 1029, The current If-Modified-Since header parsing only tries RFC2822 via
DateTime::parse_from_rfc2822, which misses RFC3339 timestamps (used by
Smithy/POST clients); update the parsing code that sets last_modified to first
attempt parse_from_rfc2822 and if that fails attempt
DateTime::parse_from_rfc3339 (converting to Utc) so both formats are accepted,
and apply the same change to the equivalent parsing block referenced for the
POST/Smithy flow (the code using DateTime::parse_from_rfc2822 and the
last_modified variable).
smithy/patches/python.patch (1)

10-10: ⚠️ Potential issue | 🟡 Minor

Clarify VERSION provisioning for local development builds.

The CI/CD pipeline in .github/workflows/release.yaml explicitly sets VERSION before all Python SDK builds (lines 492, 503, 526), so the release process is not fragile. However, local development builds running uv build without VERSION set will fail. Consider either adding a default fallback version in the Hatch configuration or documenting the required VERSION environment variable in the SDK README for developers building locally.

Also applies to: 18-20

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@smithy/patches/python.patch` at line 10, The project currently relies on the
Hatch dynamic version key dynamic = ["version"] which fails when VERSION is not
set for local uv build; fix by providing a safe fallback for VERSION in the
Hatch configuration (so dynamic resolution uses a default like a dev/0.0.0 value
when the VERSION env var is absent) or alternatively add a clear note in the SDK
README that developers must export VERSION before running uv build; update the
hatch config entry that references dynamic = ["version"] and/or the README to
ensure local builds do not fail.
crates/frontend/src/pages/experiment_group_listing/filter.rs (1)

371-378: ⚠️ Potential issue | 🟠 Major

Reset misses new dimension/context state

Line [375]-[378] resets only classic filters. The newly added context filters remain active because dimension_params_rws, dimension_buffer_rws, and context_rws are not cleared.

Suggested fix
                     <Button
                         class="h-12 w-48"
                         text="Reset"
                         icon_class="ri-restart-line"
                         on_click=move |event: MouseEvent| {
                             close_drawer("experiment_group_filter_drawer");
                             event.prevent_default();
                             batch(|| {
                                 filters_rws.set(ExpGroupFilters::default());
+                                dimension_params_rws.set(DimensionQuery::default());
                                 pagination_params_rws.update(|f| f.reset_page());
                                 filters_buffer_rws.set(ExpGroupFilters::default());
+                                dimension_buffer_rws.set(DimensionQuery::default());
+                                context_rws.set(Conditions::default());
                             });
                         }
                     />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/frontend/src/pages/experiment_group_listing/filter.rs` around lines
371 - 378, The reset handler currently only clears classic filters (filters_rws,
filters_buffer_rws) and resets pagination, but leaves the new context/dimension
state intact; update the on_click closure that calls close_drawer(...) so it
also clears dimension_params_rws, dimension_buffer_rws, and context_rws (e.g.,
set them to their defaults or empty state) alongside calling
ExpGroupFilters::default() and pagination_params_rws.update(|f| f.reset_page())
to fully reset both classic and new context/dimension filters.
🧹 Nitpick comments (2)
crates/service_utils/src/service/types.rs (1)

41-75: Well-structured header handling centralization.

The AppHeader implementation correctly handles date formatting based on client type (RFC3339 for Smithy, RFC2822 for standard HTTP).

Minor nit on line 71: .clone() is unnecessary for i64 since to_string() takes &self.

🔧 Optional: Remove unnecessary clone
     pub fn add_config_version(
         config_version: &Option<i64>,
         resp_builder: &mut HttpResponseBuilder,
     ) {
         if let Some(val) = config_version {
             resp_builder.insert_header((
                 Self::XConfigVersion.to_string(),
-                val.clone().to_string(),
+                val.to_string(),
             ));
         }
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/service_utils/src/service/types.rs` around lines 41 - 75, In
AppHeader::add_config_version the .clone() on the i64 is unnecessary; change the
insert_header call to pass val.to_string() (or &val.to_string()) without cloning
the i64 so you don't clone the integer, i.e. update the code in
add_config_version that references config_version / val and XConfigVersion to
remove .clone() before to_string() while keeping the same
resp_builder.insert_header(...) usage with HttpResponseBuilder.
crates/frontend/src/pages/experiment_group_listing.rs (1)

258-277: Silent error handling may mask API failures.

Both experiment_groups::list and dimensions::list use .unwrap_or_default() which silently swallows any API errors, returning empty data instead. While this provides resilience for the UI, it could make debugging production issues difficult since users would see empty results with no indication of the underlying failure.

Consider logging errors before defaulting, or surfacing a user-visible error state:

let experiment_groups = match experiment_groups::list(
    &filters,
    &pagination,
    &dimension_params,
    &workspace,
    &org_id,
).await {
    Ok(data) => data,
    Err(e) => {
        logging::error!("Failed to fetch experiment groups: {:?}", e);
        PaginatedResponse::default()
    }
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/frontend/src/pages/experiment_group_listing.rs` around lines 258 -
277, The current use of .unwrap_or_default() on experiment_groups::list and
dimensions::list silently swallows API errors; update the async block so each
call to experiment_groups::list and dimensions::list is handled via match (or ?
if the surrounding function returns Result) and on Err(e) call a logging macro
(e.g., logging::error!) with a clear message including the error and context
(filters/pagination/workspace/org_id), then return a sensible default (e.g.,
PaginatedResponse::default()) or propagate the error up so the UI can surface
it; adjust CombinedResource construction accordingly to use the handled results.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@clients/haskell/sdk/Io/Superposition/Model/GetConfigInput.hs`:
- Line 146: The If-Modified-Since header is being serialized from a UTCTime via
(if_modified_since self) using Io.Superposition.Utility.serHeader, but HTTP
requires RFC7231 format; update the code so the value passed to
Io.Superposition.Utility.serHeader is an HTTPDate (or a formatted RFC7231
string) instead of raw UTCTime: either change the field type to HTTPDate where
GetConfigInput defines if_modified_since or call the existing
formatHTTPDate/HTTPDate conversion function on (if_modified_since self) just
before passing it to Io.Superposition.Utility.serHeader so the header uses
formatHTTPDate output.

In `@clients/haskell/sdk/Io/Superposition/Model/GetConfigOutput.hs`:
- Line 16: GetConfigOutput's audit_id field and setAuditId accessor were
intentionally removed; update any code that expects audit_id on the
GetConfigOutput model (and any callers of setAuditId) to stop accessing or
setting that field. Search for references to GetConfigOutput.audit_id,
setAuditId, or variables named auditId in code paths handling GetConfigOutput
and remove or conditionally gate those usages—if the audit id is still needed
for GetResolvedConfig/GetResolvedConfigWithIdentifier flows, move access to
those models or to the HTTP header handling layer that parses the optional audit
header. Also update affected tests and documentation to reflect that
GetConfigOutput no longer contains audit_id.

In `@clients/haskell/sdk/Io/Superposition/Model/ListExperimentGroupsInput.hs`:
- Line 248: The If-Modified-Since header is being serialized using the UTCTime
JSON SerDe (encodeTrimQuotes/quoteAndDecode) which produces RFC3339 instead of
the required RFC2822 HTTP-date; update the UTCTime SerDe (the SerDe instance for
UTCTime in Utility.hs) or create a header-specific codec so that
Io.Superposition.Utility.serHeader emits HTTP-date formatted timestamps (use
formatTime/parseTimeM with defaultTimeLocale and the RFC2822 pattern or reuse
the existing HTTPDate type/its SerDe), and change the call sites that build the
"If-Modified-Since" header (e.g., the code that calls
Io.Superposition.Utility.serHeader "If-Modified-Since" in
ListExperimentGroupsInput, ListExperimentInput, GetConfigInput) to use this
HTTP-date serializer instead of the JSON encoder.

In `@clients/haskell/sdk/Io/Superposition/Model/ListExperimentGroupsOutput.hs`:
- Around line 115-123: The SDK currently hardcodes expectedStatus = status200
for ListExperimentGroups which prevents 304 responses from being treated as a
valid outcome; update the operation's response parsing so that parseOutput (and
the expectedStatus handling) accepts 304 as a valid status and maps it to a
distinct outcome instead of routing to getErrorParser. Concretely, modify the
code that sets expectedStatus for the ListExperimentGroups operation to accept
both status200 and status304 (or add an alternate response constructor) and
update the ListExperimentGroupsOutput parsing logic (the
ListExperimentGroupsOutput constructor/parseOutput path referenced in
Io.Superposition.Model.ListExperimentGroupsOutput and the
parseOutput/getErrorParser flow) to return a 304-specific result (or a union
variant) so callers can detect and handle Not Modified separately. Ensure the
metadata still contains raw status and preserve existing behavior for 200.

In `@clients/haskell/sdk/Io/Superposition/Model/ListExperimentOutput.hs`:
- Around line 115-123: The last-modified header is RFC7231 HTTP-date, so update
the ListExperimentOutput model to use Io.Superposition.Utility.HTTPDate for the
last_modified_at field (instead of Data.Time.UTCTime) and change its
deserialization in the deSerHeader "last-modified" call to produce an HTTPDate
(either by using the utility's HTTP-date-aware header deserializer or by calling
Io.Superposition.Utility.parseHTTPDate on the header string before assigning to
last_modified_at); ensure you update the type reference (last_modified_at) and
the deserialization site (the var0 assignment from deSerHeader "last-modified")
to use Io.Superposition.Utility.HTTPDate/parseHTTPDate so valid RFC7231 dates
parse at runtime.

In `@clients/python/sdk/superposition_sdk/_private/schemas.py`:
- Around line 1720-1728: The timestamp members like if_modified_since that
target DATE_TIME are being serialized as RFC3339 because DATE_TIME is annotated
with `@timestampFormat`("date-time"); update each member-level definition (e.g.,
the if_modified_since member) to add a member-level
`@timestampFormat`("http-date") annotation or change the member target to the
HttpDate shape so the generated client emits RFC2822/http-date for headers like
If-Modified-Since and Last-Modified, then regenerate the Smithy-generated code;
look for other similar members that target DATE_TIME (the other occurrences
flagged in the review) and apply the same per-member
`@timestampFormat`("http-date") fix.

In `@crates/experimentation_platform/src/api/experiment_groups/handlers.rs`:
- Around line 336-352: The cache key used for both the list payload and the
last-modified timestamp causes type confusion because read_through_cache is
storing an Option<DateTime<Utc>> under the same key used to cache
PaginatedResponse<ExperimentGroup>; change the storage so the last-modified
value uses its own distinct key (e.g. suffix like
EXPERIMENT_GROUPS_LAST_MODIFIED_KEY) or always read the timestamp directly from
the DB instead of reusing EXPERIMENT_GROUPS_LIST_KEY_SUFFIX, update locations
using read_through_cache (the call at
read_through_cache::<Option<DateTime<Utc>>> and the later read of the list) to
use the new key or DB fetch, and ensure put_experiment_groups_in_redis
invalidates or sets both keys consistently so deserialization never sees the
wrong payload type.
- Around line 369-375: The shared Redis fast path is incorrectly used for
requests that include context-filtered dimension_params (populated for non-GET
via body.and_then(...).context), causing context-specific subsets to be cached
globally; update the logic that decides to reuse the workspace-wide list cache
(the condition around the Redis fast path at/after where Lines 381-402 are
evaluated) to also require that dimension_params is empty (e.g., check
dimension_params.is_empty()) before using the shared cache so any request with a
non-empty dimension_params bypasses Redis and uses the per-request path.

In `@crates/superposition_sdk/src/protocol_serde/shape_get_config.rs`:
- Around line 80-91: The generated code is using
::aws_smithy_types::date_time::Format::DateTime for the if_modified_since
header; change the Smithy model so the timestamp member "if_modified_since" is
defined with the HTTP-date timestamp format (e.g. set timestampFormat =
"http-date" or the equivalent HttpDate trait on that member) so the generated
code will use ::aws_smithy_types::date_time::Format::HttpDate; update the Smithy
shape for the request/input that contains the if_modified_since member and then
regenerate the Rust code to pick up the new format.

In `@docs/docs/api/Superposition.openapi.json`:
- Around line 172-180: Remove the "If-Modified-Since" header from the POST
operation definitions (the header object named "If-Modified-Since" in
Superposition.openapi.json) and stop documenting 304 responses for those POST
endpoints; instead, move any cache revalidation semantics to the corresponding
GET/HEAD routes or define a POST-specific contract (e.g., explicit conditional
request/response fields) that does not rely on If-Modified-Since/304 per RFC
9110. Ensure all occurrences of the "If-Modified-Since" header and any
referenced 304 response entries in the file (including the other ranges noted)
are deleted or relocated to GET/HEAD operation objects and update the operation
descriptions to reflect the change.

In `@smithy/models/config.smithy`:
- Around line 87-90: Add the `@timestampFormat`("http-date") annotation to the
if_modified_since DateTime header field so it is serialized as an HTTP-date
(RFC2822) rather than RFC3339; update the field declaration for
if_modified_since (the one annotated with `@httpHeader`("If-Modified-Since") and
`@notProperty`) in the models for the GetConfig, ListExperiment, and
ListExperimentGroups operations to include `@timestampFormat`("http-date") so
Python/Rust/JS SDKs emit the correct format.

In `@smithy/models/experiments.smithy`:
- Line 321: The API contract for the ListExperiment operation was changed from
GET /experiments to POST /experiments/list which is a breaking change; update
the service and client surface to avoid breaking consumers by either (a)
restoring/supporting the old GET /experiments endpoint in the backend routing
(and keep the new POST /experiments/list) during a transition, (b) update all
SDKs/clients, docs, and integration tests to use the new POST endpoint and
prepare a major version bump, and/or (c) add explicit migration notices in the
API changelog and README; locate the smithy operation definition for
ListExperiment (the `@http`(method: "POST", uri: "/experiments/list") annotation)
and ensure corresponding server routes, SDK generation, tests, and documentation
are updated to reflect the chosen migration strategy.

---

Outside diff comments:
In `@clients/haskell/sdk/Io/Superposition/Model/GetConfigInput.hs`:
- Around line 137-148: The request builder for GetConfigInput currently sends an
"If-Modified-Since" header (see IntoRequestBuilder/GetConfigInput and
intoRequestBuilder calling serHeader "If-Modified-Since") but there is no 304
handling; update the response parsing for this operation (the GetConfigOutput
parse function or parseOutput for GetConfigInput/GetConfigOutput) to explicitly
handle HTTP 304 by returning an appropriate cached/empty/default GetConfigOutput
(or a sentinel indicating "NotModified") instead of treating 304 as an
unexpected status, or if conditional requests are not supported, remove the
serHeader "If-Modified-Since" from intoRequestBuilder to avoid sending
conditional requests altogether. Ensure you reference and update the parse
function that currently rejects non-2xx responses so it treats 304 as a valid
branch.

In `@clients/haskell/sdk/SuperpositionSDK.cabal`:
- Line 3: The package still lists "version: 0.0.1" in SuperpositionSDK.cabal
despite removing modules from exposed-modules (a breaking public API change);
update the version field in SuperpositionSDK.cabal to the next release version
appropriate for a breaking change (per your release policy) so downstream
consumers can detect the change, e.g., replace "version: 0.0.1" with the new
version string.

In `@crates/experimentation_platform/src/api/experiments/handlers.rs`:
- Around line 1021-1029: The current If-Modified-Since header parsing only tries
RFC2822 via DateTime::parse_from_rfc2822, which misses RFC3339 timestamps (used
by Smithy/POST clients); update the parsing code that sets last_modified to
first attempt parse_from_rfc2822 and if that fails attempt
DateTime::parse_from_rfc3339 (converting to Utc) so both formats are accepted,
and apply the same change to the equivalent parsing block referenced for the
POST/Smithy flow (the code using DateTime::parse_from_rfc2822 and the
last_modified variable).

In `@crates/frontend/src/pages/experiment_group_listing/filter.rs`:
- Around line 371-378: The reset handler currently only clears classic filters
(filters_rws, filters_buffer_rws) and resets pagination, but leaves the new
context/dimension state intact; update the on_click closure that calls
close_drawer(...) so it also clears dimension_params_rws, dimension_buffer_rws,
and context_rws (e.g., set them to their defaults or empty state) alongside
calling ExpGroupFilters::default() and pagination_params_rws.update(|f|
f.reset_page()) to fully reset both classic and new context/dimension filters.

In `@smithy/patches/python.patch`:
- Line 10: The project currently relies on the Hatch dynamic version key dynamic
= ["version"] which fails when VERSION is not set for local uv build; fix by
providing a safe fallback for VERSION in the Hatch configuration (so dynamic
resolution uses a default like a dev/0.0.0 value when the VERSION env var is
absent) or alternatively add a clear note in the SDK README that developers must
export VERSION before running uv build; update the hatch config entry that
references dynamic = ["version"] and/or the README to ensure local builds do not
fail.

---

Nitpick comments:
In `@crates/frontend/src/pages/experiment_group_listing.rs`:
- Around line 258-277: The current use of .unwrap_or_default() on
experiment_groups::list and dimensions::list silently swallows API errors;
update the async block so each call to experiment_groups::list and
dimensions::list is handled via match (or ? if the surrounding function returns
Result) and on Err(e) call a logging macro (e.g., logging::error!) with a clear
message including the error and context (filters/pagination/workspace/org_id),
then return a sensible default (e.g., PaginatedResponse::default()) or propagate
the error up so the UI can surface it; adjust CombinedResource construction
accordingly to use the handled results.

In `@crates/service_utils/src/service/types.rs`:
- Around line 41-75: In AppHeader::add_config_version the .clone() on the i64 is
unnecessary; change the insert_header call to pass val.to_string() (or
&val.to_string()) without cloning the i64 so you don't clone the integer, i.e.
update the code in add_config_version that references config_version / val and
XConfigVersion to remove .clone() before to_string() while keeping the same
resp_builder.insert_header(...) usage with HttpResponseBuilder.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 77c5dcba-1dc6-42a7-8009-c20b3e5e5c24

📥 Commits

Reviewing files that changed from the base of the PR and between 95468ee and e7359a1.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (108)
  • clients/haskell/sdk/Io/Superposition/Command/GetConfigFast.hs
  • clients/haskell/sdk/Io/Superposition/Model/GetConfigFastInput.hs
  • clients/haskell/sdk/Io/Superposition/Model/GetConfigFastOutput.hs
  • clients/haskell/sdk/Io/Superposition/Model/GetConfigInput.hs
  • clients/haskell/sdk/Io/Superposition/Model/GetConfigOutput.hs
  • clients/haskell/sdk/Io/Superposition/Model/ListExperimentGroupsInput.hs
  • clients/haskell/sdk/Io/Superposition/Model/ListExperimentGroupsOutput.hs
  • clients/haskell/sdk/Io/Superposition/Model/ListExperimentInput.hs
  • clients/haskell/sdk/Io/Superposition/Model/ListExperimentOutput.hs
  • clients/haskell/sdk/SuperpositionSDK.cabal
  • clients/java/sdk/src/main/java/io/juspay/superposition/client/SuperpositionAsyncClient.java
  • clients/java/sdk/src/main/java/io/juspay/superposition/client/SuperpositionAsyncClientImpl.java
  • clients/java/sdk/src/main/java/io/juspay/superposition/client/SuperpositionClient.java
  • clients/java/sdk/src/main/java/io/juspay/superposition/client/SuperpositionClientImpl.java
  • clients/java/sdk/src/main/java/io/juspay/superposition/model/Config.java
  • clients/java/sdk/src/main/java/io/juspay/superposition/model/ExperimentGroup.java
  • clients/java/sdk/src/main/java/io/juspay/superposition/model/Experiments.java
  • clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigFast.java
  • clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigFastInput.java
  • clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigFastOutput.java
  • clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigInput.java
  • clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigOutput.java
  • clients/java/sdk/src/main/java/io/juspay/superposition/model/ListExperiment.java
  • clients/java/sdk/src/main/java/io/juspay/superposition/model/ListExperimentGroups.java
  • clients/java/sdk/src/main/java/io/juspay/superposition/model/ListExperimentGroupsInput.java
  • clients/java/sdk/src/main/java/io/juspay/superposition/model/ListExperimentGroupsOutput.java
  • clients/java/sdk/src/main/java/io/juspay/superposition/model/ListExperimentInput.java
  • clients/java/sdk/src/main/java/io/juspay/superposition/model/ListExperimentOutput.java
  • clients/javascript/sdk/src/Superposition.ts
  • clients/javascript/sdk/src/SuperpositionClient.ts
  • clients/javascript/sdk/src/commands/GetConfigCommand.ts
  • clients/javascript/sdk/src/commands/GetConfigFastCommand.ts
  • clients/javascript/sdk/src/commands/ListExperimentCommand.ts
  • clients/javascript/sdk/src/commands/ListExperimentGroupsCommand.ts
  • clients/javascript/sdk/src/commands/index.ts
  • clients/javascript/sdk/src/models/models_0.ts
  • clients/javascript/sdk/src/protocols/Aws_restJson1.ts
  • clients/python/sdk/superposition_sdk/_private/schemas.py
  • clients/python/sdk/superposition_sdk/client.py
  • clients/python/sdk/superposition_sdk/config.py
  • clients/python/sdk/superposition_sdk/deserialize.py
  • clients/python/sdk/superposition_sdk/models.py
  • clients/python/sdk/superposition_sdk/serialize.py
  • crates/context_aware_config/Cargo.toml
  • crates/context_aware_config/src/api/config/handlers.rs
  • crates/context_aware_config/src/api/config/helpers.rs
  • crates/context_aware_config/src/api/context/handlers.rs
  • crates/experimentation_platform/src/api/experiment_groups/handlers.rs
  • crates/experimentation_platform/src/api/experiments/handlers.rs
  • crates/frontend/src/api.rs
  • crates/frontend/src/components/experiment_form.rs
  • crates/frontend/src/pages/experiment_group_listing.rs
  • crates/frontend/src/pages/experiment_group_listing/filter.rs
  • crates/service_utils/src/helpers.rs
  • crates/service_utils/src/redis.rs
  • crates/service_utils/src/service/types.rs
  • crates/superposition/src/resolve/handlers.rs
  • crates/superposition_sdk/src/client.rs
  • crates/superposition_sdk/src/client/customize.rs
  • crates/superposition_sdk/src/client/get_config.rs
  • crates/superposition_sdk/src/client/get_config_fast.rs
  • crates/superposition_sdk/src/client/list_experiment.rs
  • crates/superposition_sdk/src/client/list_experiment_groups.rs
  • crates/superposition_sdk/src/error_meta.rs
  • crates/superposition_sdk/src/operation.rs
  • crates/superposition_sdk/src/operation/get_config/_get_config_input.rs
  • crates/superposition_sdk/src/operation/get_config/_get_config_output.rs
  • crates/superposition_sdk/src/operation/get_config/builders.rs
  • crates/superposition_sdk/src/operation/get_config_fast.rs
  • crates/superposition_sdk/src/operation/get_config_fast/_get_config_fast_input.rs
  • crates/superposition_sdk/src/operation/get_config_fast/_get_config_fast_output.rs
  • crates/superposition_sdk/src/operation/get_config_fast/builders.rs
  • crates/superposition_sdk/src/operation/list_experiment.rs
  • crates/superposition_sdk/src/operation/list_experiment/_list_experiment_input.rs
  • crates/superposition_sdk/src/operation/list_experiment/_list_experiment_output.rs
  • crates/superposition_sdk/src/operation/list_experiment/builders.rs
  • crates/superposition_sdk/src/operation/list_experiment_groups.rs
  • crates/superposition_sdk/src/operation/list_experiment_groups/_list_experiment_groups_input.rs
  • crates/superposition_sdk/src/operation/list_experiment_groups/_list_experiment_groups_output.rs
  • crates/superposition_sdk/src/operation/list_experiment_groups/builders.rs
  • crates/superposition_sdk/src/protocol_serde.rs
  • crates/superposition_sdk/src/protocol_serde/shape_get_config.rs
  • crates/superposition_sdk/src/protocol_serde/shape_get_config_fast.rs
  • crates/superposition_sdk/src/protocol_serde/shape_get_config_fast_output.rs
  • crates/superposition_sdk/src/protocol_serde/shape_get_config_output.rs
  • crates/superposition_sdk/src/protocol_serde/shape_list_experiment.rs
  • crates/superposition_sdk/src/protocol_serde/shape_list_experiment_groups.rs
  • crates/superposition_sdk/src/protocol_serde/shape_list_experiment_groups_input.rs
  • crates/superposition_sdk/src/protocol_serde/shape_list_experiment_groups_output.rs
  • crates/superposition_sdk/src/protocol_serde/shape_list_experiment_input.rs
  • crates/superposition_sdk/src/protocol_serde/shape_list_experiment_output.rs
  • crates/superposition_sdk/src/serde_util.rs
  • crates/superposition_sdk/src/types.rs
  • crates/superposition_sdk/src/types/builders.rs
  • crates/superposition_types/src/api/experiment_groups.rs
  • crates/superposition_types/src/api/experiments.rs
  • crates/superposition_types/src/database/models/experimentation.rs
  • docs/docs/api/Superposition.openapi.json
  • docs/docs/api/get-config-fast.api.mdx
  • docs/docs/api/get-config.api.mdx
  • docs/docs/api/list-experiment-groups.api.mdx
  • docs/docs/api/list-experiment.api.mdx
  • docs/docs/api/sidebar.ts
  • smithy/models/config.smithy
  • smithy/models/experiment_groups.smithy
  • smithy/models/experiments.smithy
  • smithy/patches/java.patch
  • smithy/patches/python.patch
💤 Files with no reviewable changes (30)
  • crates/service_utils/src/helpers.rs
  • crates/superposition_sdk/src/operation.rs
  • clients/java/sdk/src/main/java/io/juspay/superposition/model/Experiments.java
  • crates/superposition_sdk/src/client/get_config_fast.rs
  • crates/superposition_sdk/src/error_meta.rs
  • clients/javascript/sdk/src/SuperpositionClient.ts
  • clients/haskell/sdk/Io/Superposition/Command/GetConfigFast.hs
  • crates/superposition_sdk/src/operation/get_config/_get_config_output.rs
  • clients/javascript/sdk/src/commands/index.ts
  • crates/superposition_sdk/src/client/customize.rs
  • clients/javascript/sdk/src/commands/GetConfigFastCommand.ts
  • crates/superposition_sdk/src/client.rs
  • clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigFastOutput.java
  • crates/superposition_sdk/src/protocol_serde/shape_get_config_output.rs
  • crates/superposition_sdk/src/protocol_serde/shape_get_config_fast_output.rs
  • docs/docs/api/get-config-fast.api.mdx
  • crates/superposition_sdk/src/operation/get_config_fast/_get_config_fast_input.rs
  • clients/java/sdk/src/main/java/io/juspay/superposition/client/SuperpositionAsyncClient.java
  • clients/python/sdk/superposition_sdk/client.py
  • clients/javascript/sdk/src/Superposition.ts
  • crates/context_aware_config/Cargo.toml
  • clients/java/sdk/src/main/java/io/juspay/superposition/client/SuperpositionClient.java
  • crates/superposition_sdk/src/operation/get_config_fast.rs
  • crates/superposition_sdk/src/protocol_serde/shape_get_config_fast.rs
  • clients/haskell/sdk/Io/Superposition/Model/GetConfigFastInput.hs
  • clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigFastInput.java
  • clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigFast.java
  • crates/superposition_sdk/src/operation/get_config_fast/_get_config_fast_output.rs
  • crates/superposition_sdk/src/operation/get_config_fast/builders.rs
  • clients/haskell/sdk/Io/Superposition/Model/GetConfigFastOutput.hs

Io.Superposition.Utility.serQuery "prefix" (prefix self)
Io.Superposition.Utility.serQuery "version" (version self)
Io.Superposition.Utility.serHeader "x-workspace" (workspace_id self)
Io.Superposition.Utility.serHeader "If-Modified-Since" (if_modified_since self)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for serHeader implementation to verify UTCTime formatting
ast-grep --pattern $'serHeader $_ $_ = $_'

# Also check if there's any custom UTCTime serialization
rg -n "UTCTime|formatTime|RFC" --type hs -C 3

Repository: juspay/superposition

Length of output: 50377


🏁 Script executed:

# Find Utility module files
find . -name "*Utility*" -type f | grep -E "\.hs$"

# Search for serHeader function definition
rg -n "serHeader" --type hs -A 5 -B 2

# Search for any HTTP header formatting functions
rg -n "formatTime|toHTTPDate|RFC.*7231" --type hs

Repository: juspay/superposition

Length of output: 50376


🏁 Script executed:

# Find SerializeParameter class and instances
rg -n "class SerializeParameter|instance.*SerializeParameter" --type hs -A 3

# Search for toHttpApiData or similar conversion functions for UTCTime
rg -n "instance.*ToHttpApiData|instance.*SerializeParameter.*UTCTime" --type hs -A 5

# Look at the serParameter function implementation
sed -n '200,260p' clients/haskell/sdk/Io/Superposition/Utility.hs

Repository: juspay/superposition

Length of output: 5174


🏁 Script executed:

# Find SerDe typeclass and UTCTime instance
rg -n "class SerDe|instance.*SerDe.*UTCTime" --type hs -A 5

# Search for serializeElement function
rg -n "serializeElement" --type hs -B 2 -A 3

# Look for any UTCTime related serialization
rg -n "UTCTime" clients/haskell/sdk/Io/Superposition/Utility.hs -B 2 -A 2

Repository: juspay/superposition

Length of output: 50376


🏁 Script executed:

# Find encodeTrimQuotes implementation
sed -n '131,137p' clients/haskell/sdk/Io/Superposition/Utility.hs

# Look for HTTPDate type definition and any imports related to date formatting
rg -n "encodeTrimQuotes|HTTPDate|formatTime" clients/haskell/sdk/Io/Superposition/Utility.hs -B 2 -A 5

Repository: juspay/superposition

Length of output: 2469


🏁 Script executed:

# Find GetConfigInput and check the type of if_modified_since
rg -n "if_modified_since" clients/haskell/sdk/Io/Superposition/Model/GetConfigInput.hs -B 5 -A 2 | head -40

Repository: juspay/superposition

Length of output: 1691


Use HTTPDate or implement RFC 7231 formatting for the If-Modified-Since header.

The if_modified_since field is Data.Time.UTCTime, which serializes to ISO 8601 format (e.g., 2024-03-20T10:30:00Z) via JSON encoding. However, the HTTP If-Modified-Since header requires RFC 7231 format (e.g., Sun, 06 Nov 1994 08:49:37 GMT). The codebase already has an HTTPDate type with proper formatHTTPDate serialization. Either change the field type to HTTPDate or implement custom header serialization for UTCTime that converts to RFC 7231 format.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@clients/haskell/sdk/Io/Superposition/Model/GetConfigInput.hs` at line 146,
The If-Modified-Since header is being serialized from a UTCTime via
(if_modified_since self) using Io.Superposition.Utility.serHeader, but HTTP
requires RFC7231 format; update the code so the value passed to
Io.Superposition.Utility.serHeader is an HTTPDate (or a formatted RFC7231
string) instead of raw UTCTime: either change the field type to HTTPDate where
GetConfigInput defines if_modified_since or call the existing
formatHTTPDate/HTTPDate conversion function on (if_modified_since self) just
before passing it to Io.Superposition.Utility.serHeader so the header uses
formatHTTPDate output.

version,
last_modified,
audit_id
last_modified
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if any code depends on audit_id from GetConfigOutput
rg -n 'GetConfigOutput.*audit_id|audit_id.*GetConfigOutput' --type hs

Repository: juspay/superposition

Length of output: 46


🏁 Script executed:

# View the GetConfigOutput.hs file to verify the changes
head -100 clients/haskell/sdk/Io/Superposition/Model/GetConfigOutput.hs

Repository: juspay/superposition

Length of output: 3948


🏁 Script executed:

# Check GetResolvedConfigOutput.hs to confirm it still has audit_id
grep -n "audit_id\|setAuditId" clients/haskell/sdk/Io/Superposition/Model/GetResolvedConfigOutput.hs | head -20

Repository: juspay/superposition

Length of output: 695


🏁 Script executed:

# Look for Smithy specs related to these models
find . -name "*.smithy" -o -name "*spec*" | grep -i config | head -20

Repository: juspay/superposition

Length of output: 131


🏁 Script executed:

# Check git log for context about why this change was made
git log --oneline -20 -- clients/haskell/sdk/Io/Superposition/Model/GetConfigOutput.hs 2>/dev/null | head -10

Repository: juspay/superposition

Length of output: 97


🏁 Script executed:

# View the config.smithy file to see the GetConfigOutput and GetResolvedConfigOutput definitions
cat smithy/models/config.smithy

Repository: juspay/superposition

Length of output: 7218


🏁 Script executed:

# Check if there are any other references or comments explaining the difference
rg -n "GetConfigOutput|GetResolvedConfigOutput" smithy/ -A 5 -B 5 | head -80

Repository: juspay/superposition

Length of output: 46


Breaking change: audit_id field removed from GetConfigOutput.

The audit_id field and setAuditId function have been removed from this model. This is a breaking change for SDK consumers who were accessing the audit_id field from GetConfigOutput. This removal is intentional per the Smithy specification: the GetConfig operation does not include audit_id in its output, whereas GetResolvedConfig and GetResolvedConfigWithIdentifier operations retain it as an optional HTTP header field.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@clients/haskell/sdk/Io/Superposition/Model/GetConfigOutput.hs` at line 16,
GetConfigOutput's audit_id field and setAuditId accessor were intentionally
removed; update any code that expects audit_id on the GetConfigOutput model (and
any callers of setAuditId) to stop accessing or setting that field. Search for
references to GetConfigOutput.audit_id, setAuditId, or variables named auditId
in code paths handling GetConfigOutput and remove or conditionally gate those
usages—if the audit id is still needed for
GetResolvedConfig/GetResolvedConfigWithIdentifier flows, move access to those
models or to the HTTP header handling layer that parses the optional audit
header. Also update affected tests and documentation to reflect that
GetConfigOutput no longer contains audit_id.

Io.Superposition.Utility.serQuery "sort_on" (sort_on self)
Io.Superposition.Utility.serQuery "name" (name self)
Io.Superposition.Utility.serQuery "page" (page self)
Io.Superposition.Utility.serHeader "If-Modified-Since" (if_modified_since self)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

root_dir="clients/haskell/sdk/Io/Superposition"
utility_file="$(fd 'Utility\.hs$' "$root_dir" | head -n1)"

if [[ -z "${utility_file}" ]]; then
  echo "Utility.hs not found under ${root_dir}" >&2
  exit 1
fi

echo "== Header/timestamp helpers in ${utility_file} =="
rg -n -C4 '\bserHeader\b|\bdeSerHeader\b|UTCTime|formatTime|parseTime|timestamp|http-date|rfc822|iso8601' "${utility_file}"

echo
echo "== Timestamp-header call sites in the generated SDK =="
rg -n -C2 'If-Modified-Since|last-modified' "${root_dir}"

Repository: juspay/superposition

Length of output: 10365


Use the correct HTTP-date format for If-Modified-Since header serialization.

The SerDe UTCTime instance at Utility.hs lines 138-140 uses JSON encoding (encodeTrimQuotes/quoteAndDecode), which produces RFC 3339 format (e.g., "2025-10-21T07:28:00Z"). However, HTTP headers require RFC 2822 format (e.g., "Wed, 21 Oct 2025 07:28:00 GMT"). Line 248 and all If-Modified-Since call sites (ListExperimentInput.hs:319, GetConfigInput.hs:146) will send incorrectly formatted timestamps, causing conditional requests to silently fail even when the server responds correctly.

The codebase defines an HTTPDate type with a SerDe instance (Utility.hs lines 142-145) but still uses JSON encoding. Replace the JSON-based serialization for HTTP timestamp headers with proper RFC 2822 formatting via formatTime/parseTimeM and the defaultTimeLocale constant (already imported at Utility.hs line 53). Use HTTPDate or create a header-specific codec that formats timestamps according to the Smithy HTTP-date specification.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@clients/haskell/sdk/Io/Superposition/Model/ListExperimentGroupsInput.hs` at
line 248, The If-Modified-Since header is being serialized using the UTCTime
JSON SerDe (encodeTrimQuotes/quoteAndDecode) which produces RFC3339 instead of
the required RFC2822 HTTP-date; update the UTCTime SerDe (the SerDe instance for
UTCTime in Utility.hs) or create a header-specific codec so that
Io.Superposition.Utility.serHeader emits HTTP-date formatted timestamps (use
formatTime/parseTimeM with defaultTimeLocale and the RFC2822 pattern or reuse
the existing HTTPDate type/its SerDe), and change the call sites that build the
"If-Modified-Since" header (e.g., the code that calls
Io.Superposition.Utility.serHeader "If-Modified-Since" in
ListExperimentGroupsInput, ListExperimentInput, GetConfigInput) to use this
HTTP-date serializer instead of the JSON encoder.

Comment on lines +115 to +123
var0 <- Io.Superposition.Utility.deSerHeader "last-modified"
var1 <- Io.Superposition.Utility.deSerField "data"
var2 <- Io.Superposition.Utility.deSerField "total_pages"
var3 <- Io.Superposition.Utility.deSerField "total_items"
pure $ ListExperimentGroupsOutput {
total_pages = var1,
total_items = var2,
data' = var0
total_pages = var2,
total_items = var3,
data' = var1,
last_modified = var0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

root_dir="clients/haskell/sdk/Io/Superposition"
utility_file="$(fd 'Utility\.hs$' "$root_dir" | head -n1)"

if [[ -z "${utility_file}" ]]; then
  echo "Utility.hs not found under ${root_dir}" >&2
  exit 1
fi

echo "== Shared response parsing/status handling =="
rg -n -C4 'FromResponseParser|expectedStatus|responseParser|status304|statusCode|responseStatus|Response|Left|throw' "${utility_file}"

echo
echo "== SDK usages around expectedStatus and conditional requests =="
rg -n -C4 'expectedStatus|status304|If-Modified-Since|Not Modified|responseParser' "${root_dir}"

Repository: juspay/superposition

Length of output: 50377


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find and examine ListExperimentGroupsOutput.hs fully
echo "=== ListExperimentGroupsOutput.hs ==="
fd 'ListExperimentGroupsOutput\.hs$' --type f
list_file=$(fd 'ListExperimentGroupsOutput\.hs$' --type f | head -n1)
if [[ -n "$list_file" ]]; then
  wc -l "$list_file"
  cat -n "$list_file" | tail -n 50
fi

echo
echo "=== GetConfigOutput.hs (conditional request endpoint) ==="
getconfig_file=$(fd 'GetConfigOutput\.hs$' --type f | head -n1)
if [[ -n "$getconfig_file" ]]; then
  wc -l "$getconfig_file"
  cat -n "$getconfig_file"
fi

echo
echo "=== Checking for 304 / Not Modified handling anywhere ==="
rg -r 'status304|304|NotModified|"304"' clients/haskell --type haskell -i

Repository: juspay/superposition

Length of output: 11991


Callers cannot detect or handle 304 Not Modified responses—the conditional request flow is broken.

The expectedStatus = status200 hardcoding on line 113 prevents the SDK from accepting 304 responses. When a 304 is received, parseOutput (Utility.hs:597–605) routes it through getErrorParser, which has no handler for 304, resulting in a generic mkUnexpectedError and no way for callers to distinguish conditional hits from true errors. The Smithy spec (experiment_groups.smithy:241–279) explicitly requires callers to handle 304 separately; this implementation makes that impossible.

The runtime does preserve raw HTTP status in metadata, but the SDK API cannot expose it here since non-200 responses are treated as errors. The architecture needs to either support multiple expectedStatus values per operation or provide an alternate response type for 304, to make the caching pattern functional.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@clients/haskell/sdk/Io/Superposition/Model/ListExperimentGroupsOutput.hs`
around lines 115 - 123, The SDK currently hardcodes expectedStatus = status200
for ListExperimentGroups which prevents 304 responses from being treated as a
valid outcome; update the operation's response parsing so that parseOutput (and
the expectedStatus handling) accepts 304 as a valid status and maps it to a
distinct outcome instead of routing to getErrorParser. Concretely, modify the
code that sets expectedStatus for the ListExperimentGroups operation to accept
both status200 and status304 (or add an alternate response constructor) and
update the ListExperimentGroupsOutput parsing logic (the
ListExperimentGroupsOutput constructor/parseOutput path referenced in
Io.Superposition.Model.ListExperimentGroupsOutput and the
parseOutput/getErrorParser flow) to return a 304-specific result (or a union
variant) so callers can detect and handle Not Modified separately. Ensure the
metadata still contains raw status and preserve existing behavior for 200.

Comment on lines +115 to +123
var0 <- Io.Superposition.Utility.deSerHeader "last-modified"
var1 <- Io.Superposition.Utility.deSerField "data"
var2 <- Io.Superposition.Utility.deSerField "total_pages"
var3 <- Io.Superposition.Utility.deSerField "total_items"
pure $ ListExperimentOutput {
total_pages = var1,
total_items = var2,
data' = var0
total_pages = var2,
total_items = var3,
data' = var1,
last_modified_at = var0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "1) Find deSerHeader implementation and type constraints"
rg -n --type=hs -C4 '\bdeSerHeader\b'

echo
echo "2) Inspect timestamp parsing helpers/usages (UTCTime, parseTimeM, HTTP-date, ISO-8601)"
rg -n --type=hs -C3 'UTCTime|parseTimeM|http-date|RFC7231|rfc822|iso8601|last-modified'

echo
echo "3) Compare sibling generated models using last-modified header"
rg -n --type=hs -C3 'deSerHeader "last-modified"|last_modified_at|last_modified'

Repository: juspay/superposition

Length of output: 50378


🏁 Script executed:

#!/bin/bash
# Find HTTPDate type definition
echo "=== HTTPDate type definition ==="
rg -n --type=hs -B3 -A8 'newtype\s+HTTPDate|data\s+HTTPDate'

echo
echo "=== quoteAndDecode and eitherDecodeStrict implementation ==="
rg -n --type=hs -B2 -A5 'quoteAndDecode|eitherDecodeStrict' | head -80

echo
echo "=== Check for FromJSON/ToJSON for UTCTime and HTTPDate ==="
rg -n --type=hs 'FromJSON.*UTCTime|FromJSON.*HTTPDate|instance.*UTCTime|instance.*HTTPDate' | head -50

echo
echo "=== Look for models using HTTPDate vs UTCTime for last-modified ==="
rg -n --type=hs 'last.modified.*::.*HTTPDate|last.modified.*::.*UTCTime' 

echo
echo "=== Search for working examples of http-date header parsing ==="
rg -n --type=hs -B2 -A2 'HTTPDate' | head -100

Repository: juspay/superposition

Length of output: 25865


🏁 Script executed:

#!/bin/bash
# Check HTTPDate and UTCTime FromJSON implementations in detail
echo "=== UTCTime FromJSON instance ==="
rg -n --type=hs -B5 -A10 'instance.*FromJSON.*UTCTime|instance.*ToJSON.*UTCTime'

echo
echo "=== Check ListExperimentOutput complete definition ==="
cat clients/haskell/sdk/Io/Superposition/Model/ListExperimentOutput.hs | head -150

echo
echo "=== Check if any models use HTTPDate for headers ==="
rg -n --type=hs 'deSerHeader.*HTTPDate|:: Io.Superposition.Utility.HTTPDate'

Repository: juspay/superposition

Length of output: 5518


Use HTTPDate type instead of UTCTime for the last-modified header field.

The last-modified header is in RFC7231 format (HTTP-date), not ISO-8601. The field last_modified_at is currently typed as Data.Time.UTCTime, which uses Aeson's ISO-8601 parser via quoteAndDecode. This will fail at runtime on valid HTTP responses. The correct type HTTPDate exists and has proper RFC7231 parsing via parseHTTPDate, but is unused across all generated models. Change the field type to Io.Superposition.Utility.HTTPDate or convert the header before deserialization.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@clients/haskell/sdk/Io/Superposition/Model/ListExperimentOutput.hs` around
lines 115 - 123, The last-modified header is RFC7231 HTTP-date, so update the
ListExperimentOutput model to use Io.Superposition.Utility.HTTPDate for the
last_modified_at field (instead of Data.Time.UTCTime) and change its
deserialization in the deSerHeader "last-modified" call to produce an HTTPDate
(either by using the utility's HTTP-date-aware header deserializer or by calling
Io.Superposition.Utility.parseHTTPDate on the header string before assigning to
last_modified_at); ensure you update the type reference (last_modified_at) and
the deserialization site (the var0 assignment from deSerHeader "last-modified")
to use Io.Superposition.Utility.HTTPDate/parseHTTPDate so valid RFC7231 dates
parse at runtime.

Comment on lines +369 to +375
let dimension_params = if req.method() == actix_web::http::Method::GET {
dimension_params.into_inner()
} else {
body.and_then(|b| b.into_inner().context)
.map(Into::into)
.unwrap_or_default()
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Exclude context-filtered requests from the shared Redis fast path.

Line 369 can populate dimension_params from body.context for POSTs, but Line 381 ignores that when deciding to reuse the workspace-wide list cache. An all=true request with a non-empty context can therefore cache a context-specific subset and return it to later requests with a different context. The minimal safe fix is to bypass Redis whenever dimension_params is non-empty.

🛠️ Minimal safe fix
-    let read_from_redis = pagination_params.all.is_some_and(|e| e) && filters.is_empty();
+    let read_from_redis = pagination_params.all.is_some_and(|e| e)
+        && filters.is_empty()
+        && dimension_params.is_empty();

Also applies to: 381-402

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/experimentation_platform/src/api/experiment_groups/handlers.rs` around
lines 369 - 375, The shared Redis fast path is incorrectly used for requests
that include context-filtered dimension_params (populated for non-GET via
body.and_then(...).context), causing context-specific subsets to be cached
globally; update the logic that decides to reuse the workspace-wide list cache
(the condition around the Redis fast path at/after where Lines 381-402 are
evaluated) to also require that dimension_params is empty (e.g., check
dimension_params.is_empty()) before using the shared cache so any request with a
non-empty dimension_params bypasses Redis and uses the per-request path.

Comment on lines +80 to +91
if let ::std::option::Option::Some(inner_5) = &input.if_modified_since {
let formatted_6 = inner_5.fmt(::aws_smithy_types::date_time::Format::DateTime)?;
let header_value = formatted_6;
let header_value: ::http::HeaderValue = header_value.parse().map_err(|err| {
::aws_smithy_types::error::operation::BuildError::invalid_field("if_modified_since", format!(
"`{}` cannot be used as a header value: {}",
&header_value,
err
))
})?;
builder = builder.header("If-Modified-Since", header_value);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Does aws_smithy_types Format::DateTime produce HTTP-date format for If-Modified-Since header?

💡 Result:

No. aws_smithy_types::date_time::Format::DateTime formats as RFC 3339 (e.g. 2019-12-16T23:48:18Z), not an HTTP-date. [1]

For an If-Modified-Since header you need an HTTP-date (If-Modified-Since = HTTP-date), so you should use Format::HttpDate (e.g. Mon, 16 Dec 2019 23:48:18 GMT). [1][2]

Example:

use aws_smithy_types::{DateTime, date_time::Format};

let ims = dt.fmt(Format::HttpDate)?; // value for If-Modified-Since

Sources: [1] https://docs.rs/aws-smithy-types/latest/aws_smithy_types/date_time/enum.Format.html [2] https://www.ietf.org/ietf-ftp/rfc/rfc7232.txt.pdf


🏁 Script executed:

head -100 crates/superposition_sdk/src/protocol_serde/shape_get_config.rs | tail -30

Repository: juspay/superposition

Length of output: 1861


Fix If-Modified-Since header format in the Smithy model.

The code uses Format::DateTime (RFC 3339: 2019-12-16T23:48:18Z), but RFC 7232 requires HTTP-date format for If-Modified-Since headers (Mon, 16 Dec 2019 23:48:18 GMT). Update the Smithy model to use Format::HttpDate instead.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/superposition_sdk/src/protocol_serde/shape_get_config.rs` around lines
80 - 91, The generated code is using
::aws_smithy_types::date_time::Format::DateTime for the if_modified_since
header; change the Smithy model so the timestamp member "if_modified_since" is
defined with the HTTP-date timestamp format (e.g. set timestampFormat =
"http-date" or the equivalent HttpDate trait on that member) so the generated
code will use ::aws_smithy_types::date_time::Format::HttpDate; update the Smithy
shape for the request/input that contains the if_modified_since member and then
regenerate the Rust code to pick up the new format.

Comment on lines +172 to +180
{
"name": "If-Modified-Since",
"in": "header",
"description": "While using this, 304 response is treated as error, which needs to be handled separately by checking the response code of the http response. This is required to make sure that clients can cache the response and avoid unnecessary calls when there are no updates.",
"schema": {
"type": "string",
"description": "While using this, 304 response is treated as error, which needs to be handled separately by checking the response code of the http response. This is required to make sure that clients can cache the response and avoid unnecessary calls when there are no updates."
}
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

What does RFC 9110 say about using If-Modified-Sinceand returning304 Not ModifiedonPOST requests?

💡 Result:

RFC 9110 restricts If-Modified-Since (IMS) to GET and HEAD:

  • IMS only applies to GET/HEAD: “A recipient MUST ignore the If-Modified-Since header field … if the request method is neither GET nor HEAD.” Therefore, on a POST request, IMS is to be ignored. [1]
  • 304 Not Modified is for conditional GET/HEAD: Status 304 (Not Modified) “indicates that a conditional GET or HEAD request has been received …” (i.e., it’s defined in terms of conditional GET/HEAD, not POST). [2]

So, per RFC 9110, you should not use If-Modified-Since on POST, and you should not return 304 Not Modified to a POST based on If-Modified-Since (since IMS must be ignored on POST, and 304 is defined for conditional GET/HEAD). [1][2]

Sources: RFC 9110 (HTTP Semantics) — If-Modified-Since (§13.1.3) and 304 Not Modified (§15.4.5). [1][2]


Don't advertise If-Modified-Since/304 on these POST operations.

RFC 9110 § 13.1.3 restricts If-Modified-Since to GET and HEAD only—recipients must ignore it on other methods. Similarly, 304 Not Modified (RFC 9110 § 15.4.5) is defined exclusively for conditional GET/HEAD requests. These POST endpoints therefore document behavior that violates HTTP semantics and is not interoperable. Additionally, the spec fails to declare a 304 response for these operations. Move cache revalidation to GET/HEAD routes, or use a different contract for these POST endpoints.

Also applies to: 1925-1931, 1952-1960, 2572-2578, 2599-2606

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/docs/api/Superposition.openapi.json` around lines 172 - 180, Remove the
"If-Modified-Since" header from the POST operation definitions (the header
object named "If-Modified-Since" in Superposition.openapi.json) and stop
documenting 304 responses for those POST endpoints; instead, move any cache
revalidation semantics to the corresponding GET/HEAD routes or define a
POST-specific contract (e.g., explicit conditional request/response fields) that
does not rely on If-Modified-Since/304 per RFC 9110. Ensure all occurrences of
the "If-Modified-Since" header and any referenced 304 response entries in the
file (including the other ranges noted) are deleted or relocated to GET/HEAD
operation objects and update the operation descriptions to reflect the change.

Comment on lines +87 to +90
@documentation("While using this, 304 response is treated as error, which needs to be handled separately by checking the response code of the http response. This is required to make sure that clients can cache the response and avoid unnecessary calls when there are no updates.")
@httpHeader("If-Modified-Since")
@notProperty
if_modified_since: DateTime
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== If-Modified-Since definitions =="
rg -n 'If-Modified-Since|if_modified_since' smithy crates clients | head -n 200

echo
echo "== Backend timestamp parsing for If-Modified-Since =="
rg -n 'parse_from_rfc2822|If-Modified-Since' crates/context_aware_config -C 3

echo
echo "== Generated Rust timestamp formatting =="
rg -n 'fmt\(.*Format::DateTime' crates/superposition_sdk/src/protocol_serde -C 2

echo
echo "== Generated JS timestamp formatting =="
rg -n '__serializeDateTime\(input\[_ims\]' clients/javascript/sdk/src/protocols/Aws_restJson1.ts -C 2

Repository: juspay/superposition

Length of output: 25338


🏁 Script executed:

# Check what Format::DateTime produces in aws-smithy
cd crates/superposition_sdk/src/protocol_serde && grep -r "Format::DateTime" --include="*.rs" | head -5

# Find __serializeDateTime in JS SDK
rg -n '__serializeDateTime' clients/javascript/sdk/src/protocols/Aws_restJson1.ts | head -3

# Find serialize_rfc3339 in Python SDK
rg -n 'def serialize_rfc3339|serialize_rfc3339' clients/python/sdk/superposition_sdk/ --include="*.py" -B 2 -A 8 | head -30

Repository: juspay/superposition

Length of output: 1601


🏁 Script executed:

# Check AWS Smithy documentation or search for datetime format constants
rg -n 'Format::DateTime|Format::HttpDate|date_time.*Format' --type rust | head -20

# Get context around Python RFC3339 serialization
rg -n 'serialize_rfc3339' clients/python/sdk/superposition_sdk/serialize.py -B 5 -A 5 | head -50

Repository: juspay/superposition

Length of output: 7292


🏁 Script executed:

# Check if there are any format trait usages in the smithy models
rg -n '@timestampFormat|Format::HttpDate' smithy/ --include="*.smithy"

# Look for any existing datetime format specs
rg -n 'http-date|rfc3339|rfc2822' smithy/ --include="*.smithy" -i

Repository: juspay/superposition

Length of output: 947


🏁 Script executed:

# Search for Format enum definition to understand what DateTime format produces
find . -name "*.rs" -type f -exec grep -l "enum Format\|pub.*DateTime.*=" {} \; 2>/dev/null | head -5

# Check the AWS Smithy types module
rg -n "DateTime|HttpDate|Format" crates/superposition_sdk/src/primitives.rs -A 5 -B 2

# Search for JavaScript serializeDateTime implementation
rg -n "__serializeDateTime|serializeDateTime" clients/ -t ts -A 10 | head -50

Repository: juspay/superposition

Length of output: 5115


🏁 Script executed:

# Try to find aws-smithy external dependency info
cat Cargo.lock | grep -A 5 "aws-smithy-types" 2>/dev/null | head -20

# Check if there's documentation about Format::DateTime in comments
rg -n "Format::DateTime|serialize.*DateTime" crates/ -B 3 -A 1 | grep -E "DateTime|Format|http-date|rfc3339|rfc2822" | head -30

Repository: juspay/superposition

Length of output: 7697


🏁 Script executed:

# Search more broadly for datetime format hints in the SDK and clients
rg -n "iso.?8601|rfc.?3339|rfc.?2822|http.?date" . -i | grep -v ".git" | head -30

Repository: juspay/superposition

Length of output: 2770


🏁 Script executed:

# Check if if_modified_since appears in other operations besides get_config
rg -n "if_modified_since: DateTime" smithy/models/ -B 5 | grep -E "@httpHeader|operation|if_modified_since"

# Verify the Rust SDK uses Format::DateTime (not HttpDate) for these operations
rg -n "if_modified_since" crates/superposition_sdk/src/protocol_serde/ | grep "Format::" 

# Check what Format::DateTime produces vs Format::HttpDate in AWS Smithy docs
# by looking at actual usage patterns
rg -n "Format::HttpDate|Format::DateTime" crates/superposition_sdk/ | head -20

Repository: juspay/superposition

Length of output: 5549


Add @timestampFormat("http-date") to if_modified_since headers

The If-Modified-Since header must use HTTP-date format (RFC2822) for server parsing, but generated SDKs currently serialize it as RFC3339:

  • Python SDK sends RFC3339 (serialize_rfc3339) but backend parses RFC2822 (DateTime::parse_from_rfc2822)
  • Rust SDK uses Format::DateTime instead of Format::HttpDate
  • JavaScript SDK uses standard Smithy datetime serialization (RFC3339 by default)

This mismatch breaks conditional GET caching (304 responses). The Smithy models already define @timestampFormat("http-date") for HTTP date fields; apply it here.

Required fix
         `@documentation`("While using this, 304 response is treated as error, which needs to be handled separately by checking the response code of the http response. This is required to make sure that clients can cache the response and avoid unnecessary calls when there are no updates.")
+        `@timestampFormat`("http-date")
         `@httpHeader`("If-Modified-Since")
         `@notProperty`
         if_modified_since: DateTime

Apply to all three operations: GetConfig, ListExperiment, ListExperimentGroups (smithy/models/config.smithy, experiments.smithy, experiment_groups.smithy).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@documentation("While using this, 304 response is treated as error, which needs to be handled separately by checking the response code of the http response. This is required to make sure that clients can cache the response and avoid unnecessary calls when there are no updates.")
@httpHeader("If-Modified-Since")
@notProperty
if_modified_since: DateTime
`@documentation`("While using this, 304 response is treated as error, which needs to be handled separately by checking the response code of the http response. This is required to make sure that clients can cache the response and avoid unnecessary calls when there are no updates.")
`@timestampFormat`("http-date")
`@httpHeader`("If-Modified-Since")
`@notProperty`
if_modified_since: DateTime
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@smithy/models/config.smithy` around lines 87 - 90, Add the
`@timestampFormat`("http-date") annotation to the if_modified_since DateTime
header field so it is serialized as an HTTP-date (RFC2822) rather than RFC3339;
update the field declaration for if_modified_since (the one annotated with
`@httpHeader`("If-Modified-Since") and `@notProperty`) in the models for the
GetConfig, ListExperiment, and ListExperimentGroups operations to include
`@timestampFormat`("http-date") so Python/Rust/JS SDKs emit the correct format.

Copilot AI review requested due to automatic review settings March 18, 2026 15:35
@ayushjain17 ayushjain17 force-pushed the fix/smithy-consistency branch from e7359a1 to a704dea Compare March 18, 2026 15:35
@ayushjain17 ayushjain17 requested a review from Datron March 18, 2026 15:36
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Aligns Smithy models, server handlers, docs, and multi-language SDKs around caching (If-Modified-Since / Last-Modified), context-based filtering for list operations, and the removal of deprecated config fast-path APIs.

Changes:

  • Updated Smithy API definitions: list endpoints moved to POST .../list, added if-modified-since request header + last-modified response header, and added request-body context for dimensional filtering.
  • Updated backend handlers/utilities to implement 304 behavior and consistent Last-Modified response headers.
  • Regenerated/updated SDKs (Rust/Java/JS/Python/Haskell) + docs + integration tests; removed GetConfigFast and audit_id from config responses.

Reviewed changes

Copilot reviewed 131 out of 132 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
tests/src/experiments.test.ts Adds 304 caching test for experiment listing
tests/src/experiment_groups.test.ts Adds 304 caching test for experiment-group listing
tests/src/config.test.ts Adds 304 caching tests + TOML/JSON config format tests
smithy/patches/java.patch Patches generated Java SDK for updated Smithy shapes
smithy/models/experiments.smithy Moves list op to collection ops; POST /list; adds headers + context + last_modified
smithy/models/experiment_groups.smithy Moves list op to collection ops; POST /list; adds headers + context + last_modified
smithy/models/config.smithy Removes GetConfigFast; adds if-modified-since; POST TOML/JSON; removes audit_id from GetConfig
docs/docs/api/sidebar.ts Removes GetConfigFast; updates HTTP method labels (GET→POST) and ordering
docs/docs/api/get-config-toml.api.mdx Updates method to POST + documents if-modified-since
docs/docs/api/get-config-json.api.mdx Updates method to POST + documents if-modified-since
docs/docs/api/get-config-fast.api.mdx Removes deprecated GetConfigFast docs
crates/superposition_types/src/database/models/experimentation.rs Implements Contextual for ExperimentGroup
crates/superposition_types/src/api/experiments.rs Adds request-body type for list context (ExperimentListRequest)
crates/superposition_types/src/api/experiment_groups.rs Adds request-body type for list context (ExpGroupListRequest) + filter field
crates/superposition_sdk/src/types/builders.rs Reorders exports (regen/format)
crates/superposition_sdk/src/types.rs Reorders exports (regen/format)
crates/superposition_sdk/src/serde_util.rs Adds defaults/error-correction for required last_modified outputs
crates/superposition_sdk/src/protocol_serde/shape_list_experiment_output.rs Adds header deserializer for last-modified
crates/superposition_sdk/src/protocol_serde/shape_list_experiment_input.rs Adds JSON body serializer for list context
crates/superposition_sdk/src/protocol_serde/shape_list_experiment_groups_output.rs Adds header deserializer for last-modified
crates/superposition_sdk/src/protocol_serde/shape_list_experiment_groups_input.rs Adds JSON body serializer for list context
crates/superposition_sdk/src/protocol_serde/shape_list_experiment_groups.rs Switches list-experiment-groups to POST + body + headers
crates/superposition_sdk/src/protocol_serde/shape_list_experiment.rs Switches list-experiment to POST + body + headers
crates/superposition_sdk/src/protocol_serde/shape_get_config_toml.rs Serializes if-modified-since header
crates/superposition_sdk/src/protocol_serde/shape_get_config_output.rs Removes audit_id header deserializer
crates/superposition_sdk/src/protocol_serde/shape_get_config_json.rs Serializes if-modified-since header
crates/superposition_sdk/src/protocol_serde/shape_get_config_fast_output.rs Removes GetConfigFast protocol serde output (deprecated op removed)
crates/superposition_sdk/src/protocol_serde/shape_get_config_fast.rs Removes GetConfigFast protocol serde (deprecated op removed)
crates/superposition_sdk/src/protocol_serde/shape_get_config.rs Adds if-modified-since header serialization; removes audit_id parsing
crates/superposition_sdk/src/protocol_serde.rs Drops GetConfigFast modules; adds list input/output modules
crates/superposition_sdk/src/operation/list_experiment_groups/builders.rs Adds fluent builder fields for if_modified_since + context
crates/superposition_sdk/src/operation/list_experiment_groups/_list_experiment_groups_output.rs Adds required last_modified field to output
crates/superposition_sdk/src/operation/list_experiment_groups/_list_experiment_groups_input.rs Adds if_modified_since + context to input
crates/superposition_sdk/src/operation/list_experiment_groups.rs Switches request to POST /list with JSON body
crates/superposition_sdk/src/operation/list_experiment/builders.rs Adds fluent builder fields for if_modified_since + context
crates/superposition_sdk/src/operation/list_experiment/_list_experiment_output.rs Adds required last_modified field to output
crates/superposition_sdk/src/operation/list_experiment/_list_experiment_input.rs Adds if_modified_since + context to input
crates/superposition_sdk/src/operation/list_experiment.rs Switches request to POST /list with JSON body
crates/superposition_sdk/src/operation/get_config_toml/builders.rs Adds fluent builder support for if_modified_since
crates/superposition_sdk/src/operation/get_config_toml/_get_config_toml_input.rs Adds if_modified_since to input
crates/superposition_sdk/src/operation/get_config_toml.rs Switches GetConfigToml to POST
crates/superposition_sdk/src/operation/get_config_json/builders.rs Adds fluent builder support for if_modified_since
crates/superposition_sdk/src/operation/get_config_json/_get_config_json_input.rs Adds if_modified_since to input
crates/superposition_sdk/src/operation/get_config_json.rs Switches GetConfigJson to POST
crates/superposition_sdk/src/operation/get_config_fast/builders.rs Removes GetConfigFast operation builders
crates/superposition_sdk/src/operation/get_config_fast/_get_config_fast_output.rs Removes GetConfigFast output type
crates/superposition_sdk/src/operation/get_config_fast/_get_config_fast_input.rs Removes GetConfigFast input type
crates/superposition_sdk/src/operation/get_config/builders.rs Adds fluent builder support for if_modified_since
crates/superposition_sdk/src/operation/get_config/_get_config_output.rs Removes audit_id from output
crates/superposition_sdk/src/operation/get_config/_get_config_input.rs Adds if_modified_since to input
crates/superposition_sdk/src/operation.rs Removes GetConfigFast module export
crates/superposition_sdk/src/error_meta.rs Removes GetConfigFast error conversions
crates/superposition_sdk/src/client/list_experiment_groups.rs Documents new input/output fields (if_modified_since, context, last_modified)
crates/superposition_sdk/src/client/list_experiment.rs Documents new input/output fields (if_modified_since, context, last_modified)
crates/superposition_sdk/src/client/get_config_toml.rs Documents if_modified_since
crates/superposition_sdk/src/client/get_config_json.rs Documents if_modified_since
crates/superposition_sdk/src/client/get_config_fast.rs Removes GetConfigFast client method
crates/superposition_sdk/src/client/get_config.rs Documents if_modified_since; removes audit_id mention
crates/superposition_sdk/src/client/customize.rs Formatting cleanup
crates/superposition_sdk/src/client.rs Removes GetConfigFast module include
crates/superposition/src/resolve/handlers.rs Switches header helpers to AppHeader; uses shared is_not_modified
crates/service_utils/src/service/types.rs Introduces AppHeader::{add_last_modified, add_config_version}
crates/service_utils/src/redis.rs Adds EXPERIMENT_GROUPS_LAST_MODIFIED_KEY_SUFFIX constant
crates/service_utils/src/helpers.rs Adds shared is_not_modified helper
crates/frontend/src/pages/experiment_group_listing.rs Adds dimension query support when listing experiment groups
crates/frontend/src/components/experiment_form.rs Passes default dimension query when fetching groups
crates/frontend/src/api.rs Adds dimension params to experiment-groups list query string
crates/experimentation_platform/src/api/experiments/handlers.rs Adds POST /list route; uses request-body context; adds Last-Modified + 304 support
crates/experimentation_platform/src/api/experiment_groups/handlers.rs Adds POST /list route; uses request-body context; adds Last-Modified + 304 support
crates/context_aware_config/src/api/context/handlers.rs Simplifies v2 request detection
crates/context_aware_config/src/api/config/helpers.rs Moves header helpers out; makes POST context optional/defaultable
crates/context_aware_config/Cargo.toml Drops unused actix-http dependency
clients/python/sdk/superposition_sdk/deserialize.py Removes GetConfigFast; adds last-modified parsing for list ops; removes audit_id parsing for GetConfig
clients/python/sdk/superposition_sdk/client.py Removes GetConfigFast operation wiring
clients/javascript/sdk/src/models/models_0.ts Removes GetConfigFast + audit_id; adds new list/config header/body fields
clients/javascript/sdk/src/commands/index.ts Removes GetConfigFast export
clients/javascript/sdk/src/commands/ListExperimentGroupsCommand.ts Updates examples/output fields (context, if_modified_since, last_modified)
clients/javascript/sdk/src/commands/ListExperimentCommand.ts Updates examples/output fields (context, if_modified_since, last_modified)
clients/javascript/sdk/src/commands/GetConfigTomlCommand.ts Adds if_modified_since to example
clients/javascript/sdk/src/commands/GetConfigJsonCommand.ts Adds if_modified_since to example
clients/javascript/sdk/src/commands/GetConfigFastCommand.ts Removes GetConfigFast command
clients/javascript/sdk/src/commands/GetConfigCommand.ts Adds if_modified_since to example; removes audit_id mention
clients/javascript/sdk/src/SuperpositionClient.ts Removes GetConfigFast from service input/output unions
clients/javascript/sdk/src/Superposition.ts Removes GetConfigFast command binding + method
clients/java/sdk/src/main/java/io/juspay/superposition/model/ListExperimentOutput.java Adds required last-modified header member
clients/java/sdk/src/main/java/io/juspay/superposition/model/ListExperimentGroupsOutput.java Adds required last-modified header member
clients/java/sdk/src/main/java/io/juspay/superposition/model/ListExperimentGroups.java Changes to POST /experiment-groups/list
clients/java/sdk/src/main/java/io/juspay/superposition/model/ListExperiment.java Changes to POST /experiments/list
clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigTomlInput.java Adds if-modified-since header
clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigToml.java Switches to POST
clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigOutput.java Removes audit_id member
clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigJsonInput.java Adds if-modified-since header
clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigJson.java Switches to POST
clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigInput.java Adds if-modified-since header
clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigFastInput.java Removes deprecated GetConfigFast input
clients/java/sdk/src/main/java/io/juspay/superposition/model/GetConfigFast.java Removes deprecated GetConfigFast operation
clients/java/sdk/src/main/java/io/juspay/superposition/model/Experiments.java Updates resource shape after list→collectionOperations move
clients/java/sdk/src/main/java/io/juspay/superposition/model/ExperimentGroup.java Updates resource shape after list→collectionOperations move
clients/java/sdk/src/main/java/io/juspay/superposition/model/Config.java Removes GetConfigFast from resource operations
clients/java/sdk/src/main/java/io/juspay/superposition/client/SuperpositionClientImpl.java Removes GetConfigFast client method
clients/java/sdk/src/main/java/io/juspay/superposition/client/SuperpositionClient.java Removes GetConfigFast from interface
clients/java/sdk/src/main/java/io/juspay/superposition/client/SuperpositionAsyncClientImpl.java Removes GetConfigFast async method
clients/java/sdk/src/main/java/io/juspay/superposition/client/SuperpositionAsyncClient.java Removes GetConfigFast from async interface
clients/haskell/sdk/SuperpositionSDK.cabal Removes GetConfigFast modules from cabal exports
clients/haskell/sdk/Io/Superposition/Model/ListExperimentOutput.hs Adds last-modified header parsing + required field
clients/haskell/sdk/Io/Superposition/Model/ListExperimentGroupsOutput.hs Adds last-modified header parsing + required field
clients/haskell/sdk/Io/Superposition/Model/GetConfigTomlInput.hs Switches to POST; adds if-modified-since header
clients/haskell/sdk/Io/Superposition/Model/GetConfigOutput.hs Removes audit_id parsing
clients/haskell/sdk/Io/Superposition/Model/GetConfigJsonInput.hs Switches to POST; adds if-modified-since header
clients/haskell/sdk/Io/Superposition/Model/GetConfigInput.hs Adds if-modified-since header
clients/haskell/sdk/Io/Superposition/Model/GetConfigFastOutput.hs Removes GetConfigFast output type
clients/haskell/sdk/Io/Superposition/Model/GetConfigFastInput.hs Removes GetConfigFast input type
clients/haskell/sdk/Io/Superposition/Command/GetConfigFast.hs Removes GetConfigFast command
Cargo.lock Removes actix-http from context_aware_config deps
Comments suppressed due to low confidence (1)

clients/java/sdk/src/main/java/io/juspay/superposition/model/Experiments.java:97

  • Experiments.collectionOperations() / $COLLECTION_OPERATIONS doesn't include the actual collection operations (ListExperiment, ApplicableVariants) after the Smithy model change, and instead duplicates $OPERATIONS. This makes the generated resource schema inconsistent with the Smithy resource definition and can break clients that rely on resource metadata.
    private static final List<Schema>$COLLECTION_OPERATIONS = List.of(UpdateOverridesExperiment.$SCHEMA,
        ConcludeExperiment.$SCHEMA,
        DiscardExperiment.$SCHEMA,
        RampExperiment.$SCHEMA,
        PauseExperiment.$SCHEMA,
        ResumeExperiment.$SCHEMA);
    private static final List<Schema> $OPERATIONS = List.of(UpdateOverridesExperiment.$SCHEMA,
        ConcludeExperiment.$SCHEMA,
        DiscardExperiment.$SCHEMA,
        RampExperiment.$SCHEMA,
        PauseExperiment.$SCHEMA,
        ResumeExperiment.$SCHEMA);
    private static final Schema $SCHEMA = Schema.createResource($ID);

    /**
     * Get an instance of this {@code ApiResource}.
     *
     * @return An instance of this class.
     */
    public static Experiments instance() {
        return $INSTANCE;
    }

    private Experiments() {}

    @Override
    public Schema schema() {
        return $SCHEMA;
    }

    @Override
    public Map<String, Schema> identifiers() {
        return $IDENTIFIERS;
    }

    @Override
    public Map<String, Schema> properties() {
        return $PROPERTIES;
    }

    @Override
    public Schema create() {
        return CreateExperiment.$SCHEMA;
    }

    @Override
    public Schema read() {
        return GetExperiment.$SCHEMA;
    }

    @Override
    public List<Schema> collectionOperations() {
        return $COLLECTION_OPERATIONS;
    }
    @Override
    public List<Schema> operations() {
        return $OPERATIONS;
    }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +831 to +842
test("list experiment groups with last_modified_after filter should return correct results", async () => {
if (!lastModifiedTime) {
throw new Error(
"Last modified time not set from previous test, cannot test if-modified-since functionality.",
);
}
const cmd = new ListExperimentGroupsCommand({
workspace_id: ENV.workspace_id,
org_id: ENV.org_id,
if_modified_since: lastModifiedTime,
});
try {
Comment on lines 1219 to +1253
@@ -1234,6 +1235,7 @@ describe("Experiments API", () => {
const exp2 = out.data?.find((exp) => exp.id === experimentId2);
expect(exp1?.experiment_group_id).toBeUndefined();
expect(exp2?.experiment_group_id).toBeUndefined();
lastModifiedTime = out.last_modified;
} catch (e: any) {
console.error(
"Error in test '9. List Experiments (Basic)':",
@@ -1242,4 +1244,28 @@ describe("Experiments API", () => {
throw e;
}
});

test("9.1. List Experiments with if-modified-since header", async () => {
if (!lastModifiedTime) {
throw new Error(
"Last modified time not set from previous test, cannot test if-modified-since functionality.",
);
}
Comment on lines +496 to +498
log::info!("last modified {last_modified:?}");
let parsed_max: Option<DateTime<Utc>> = max_created_at.and_then(nanosecond_erasure);
max_created_at.is_some() && parsed_max <= last_modified
Comment on lines +337 to +342
let max_event_timestamp = read_through_cache::<Option<DateTime<Utc>>>(
format!(
"{}{EXPERIMENT_GROUPS_LIST_KEY_SUFFIX}",
*workspace_context.schema_name
),
&workspace_context.schema_name,
Comment on lines 371 to +373
);
let read_from_redis = pagination_params.all.is_some_and(|e| e) && filters.is_empty();

Comment on lines 37 to 92
@@ -85,10 +87,9 @@ public Schema delete() {
}

@Override
public Schema list() {
return ListExperimentGroups.$SCHEMA;
public List<Schema> collectionOperations() {
return $COLLECTION_OPERATIONS;
}
@ayushjain17 ayushjain17 force-pushed the fix/smithy-consistency branch 3 times, most recently from 735cb33 to 8fc501b Compare March 19, 2026 19:19
@ayushjain17 ayushjain17 changed the title Fix/smithy consistency fix: Spec for list exp and get config endpoints Mar 20, 2026
@ayushjain17 ayushjain17 force-pushed the fix/smithy-consistency branch from 870f5d1 to 8b9e0a1 Compare March 20, 2026 14:50
@ayushjain17 ayushjain17 force-pushed the fix/smithy-consistency branch from 8b9e0a1 to 96105a6 Compare March 21, 2026 20:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants